home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
User's Choice Windows CD
/
User's Choice Windows CD (CMS Software)(1993).iso
/
misc1
/
iv26_w30.zip
/
SOURCES
/
TRAY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-12
|
54KB
|
2,190 lines
/*
* Copyright (c) 1987, 1988, 1989 Stanford University
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Stanford not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Stanford makes no representations about
* the suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
* IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Tray implementation.
*/
#include <InterViews/canvas.h>
#include <InterViews/painter.h>
#include <InterViews/shape.h>
#include <InterViews/tray.h>
inline float abs (float f) { return (f < 0) ? -f : f; }
/*************************************************************************/
class TElement {
public:
TElement(Interactor*);
TElement(TGlue*);
TElement();
~TElement();
float pos, sigma; /* ultimate values */
float nat, stretch, shrink;
boolean combinable; /* false for tray elements when calcing */
/* shape of tray having no background */
boolean leftBotHalf; /* true if represents left/bottom of a */
/* pair of elems modelling an interactor */
Interactor* owner;
TGlue* tglue;
void HSetShape();
void VSetShape();
TElement* Series(TElement*); /* series combination */
TElement* Parallel(TElement*); /* parallel combination */
void Reverse();
void Limit();
};
TElement::TElement (Interactor* i) {
owner = i;
tglue = nil;
pos = sigma = 0;
}
TElement::TElement (TGlue* tg) {
owner = nil;
tglue = tg;
pos = sigma = 0;
}
TElement::TElement () {
owner = nil;
tglue = nil;
pos = sigma = 0;
}
TElement::~TElement () {
delete tglue;
}
void TElement::HSetShape () {
Shape* s;
if (tglue == nil) {
s = owner->GetShape();
nat = float(s->width)/2;
stretch = float(s->hstretch)/2;
shrink = float(s->hshrink)/2;
} else {
s = tglue->GetShape();
nat = s->width;
stretch = s->hstretch;
shrink = s->hshrink;
}
}
void TElement::VSetShape () {
Shape* s;
if (tglue == nil) {
s = owner->GetShape();
nat = float(s->height)/2;
stretch = float(s->vstretch)/2;
shrink = float(s->vshrink)/2;
} else {
s = tglue->GetShape();
nat = s->height;
stretch = s->vstretch;
shrink = s->vshrink;
}
}
TElement* TElement::Series (TElement* e) {
TElement* combo = new TElement;
register TElement* c;
combo->combinable = combinable || e->combinable;
if (combinable && e->combinable) {
combo->nat = nat + e->nat;
combo->stretch = stretch + e->stretch;
combo->shrink = shrink + e->shrink;
} else if (combo->combinable) {
c = combinable ? this : e;
combo->nat = c->nat;
combo->stretch = c->stretch;
combo->shrink = c->shrink;
}
return combo;
}
TElement* TElement::Parallel (TElement* e) {
TElement* combo = new TElement;
register TElement* c;
float emin, emax;
emin = max(nat - shrink, e->nat - e->shrink);
emax = min(nat + stretch, e->nat + e->stretch);
combo->combinable = combinable || e->combinable;
if (combinable && e->combinable) {
combo->nat = max(nat, e->nat);
combo->stretch = max(0, int(emax - combo->nat));
combo->shrink = max(0, int(combo->nat - emin));
} else if (combo->combinable) {
c = combinable ? this : e;
combo->nat = c->nat;
combo->stretch = c->stretch;
combo->shrink = c->shrink;
}
return combo;
}
void TElement::Reverse () {
float tmp;
nat = -nat;
tmp = stretch;
stretch = shrink;
shrink = tmp;
sigma = -sigma;
pos -= nat + sigma + 1;
}
void TElement::Limit () {
sigma = min(max(-shrink, sigma), stretch);
}
/*************************************************************************/
class TList {
public:
~TList();
protected:
TList(void* = nil);
void Append(TList*);
void Prepend(TList*);
void Remove(TList*);
TList* First();
TList* Last();
TList* End();
TList* Next();
TList* Prev();
boolean Empty();
void SetContents(void*);
void* GetContents();
void Delete(void*);
TList* Find(void*);
private:
void* object;
TList* next;
TList* prev;
};
inline TList::TList (void* o) { next = this; prev = this; object = o; }
inline TList* TList::First () { return next; }
inline TList* TList::Last () { return prev; }
inline TList* TList::End () { return this; }
inline TList* TList::Next () { return next; }
inline TList* TList::Prev () { return prev; }
inline boolean TList::Empty () { return next == this; }
inline void TList::SetContents (void *o) { object = o; }
inline void* TList::GetContents () { return object; }
inline void TList::Append (TList* e) {
prev->next = e;
e->prev = prev;
e->next = this;
prev = e;
}
inline void TList::Prepend (TList* e) {
next->prev = e;
e->prev = this;
e->next = next;
next = e;
}
inline void TList::Remove (TList* e) {
e->prev->next = e->next;
e->next->prev = e->prev;
e->next = e->prev = e;
}
TList::~TList () {
TList* e;
if (!Empty()) {
e = First();
Remove(this);
delete e;
}
}
void TList::Delete (void* o) {
register TList* e;
e = Find(o);
if (e != nil) {
Remove(e);
delete e;
}
}
TList* TList::Find (void* o) {
register TList* e;
for (e = next; e != this; e = e->next) {
if (e->GetContents() == o) {
return e;
}
}
return nil;
}
/*************************************************************************/
class TElementList : public TList {
public:
TElementList(TElement* = nil);
TElementList* Copy();
boolean Includes(TElement*);
boolean Includes(Interactor*, TElement*&);
void Append(TElementList*);
void Remove(TElementList*);
TElementList* First();
TElementList* End();
TElementList* Next();
void Delete(TElement*);
boolean Empty();
boolean OnlyOne();
boolean OnlyTwo();
TElement* GetElem();
};
inline TElement* TElementList::GetElem () { return (TElement*) GetContents();}
inline void TElementList::Append (TElementList* el) { TList::Append(el); }
inline void TElementList::Remove (TElementList* el) { TList::Remove(el); }
inline void TElementList::Delete (TElement* o) { TList::Delete(o); }
inline boolean TElementList::Includes (TElement* e) { return Find(e) != nil; }
inline TElementList* TElementList::First ()
{ return (TElementList*) TList::First(); }
inline TElementList* TElementList::End ()
{ return (TElementList*) TList::End(); }
inline TElementList* TElementList::Next ()
{ return (TElementList*) TList::Next(); }
inline boolean TElementList::Empty () { return TList::Empty(); }
inline boolean TElementList::OnlyOne () { return !Empty() && First()==Last(); }
inline boolean TElementList::OnlyTwo ()
{ return !Empty() && !OnlyOne() && First()->Next() == Last(); }
TElementList::TElementList (TElement* o) : (o) { }
TElementList* TElementList::Copy () {
register TElementList* t;
TElementList* newlist = new TElementList;
for (t = First(); t != End(); t = t->Next()) {
newlist->Append(new TElementList(t->GetElem()));
}
return newlist;
}
boolean TElementList::Includes (Interactor* i, TElement*& e) {
register TElementList* t;
for (t = First(); t != End(); t = t->Next()) {
e = t->GetElem();
if (e->owner == i) {
return true;
}
}
return false;
}
/*************************************************************************/
class TTermination {
public:
Alignment alignment, toAttached;
TElement* dangling, *attached;
TTermination(Alignment, TElement*, Alignment, TElement*);
};
TTermination::TTermination (
Alignment a, TElement* d, Alignment to, TElement* e
) {
alignment = a;
dangling = d;
toAttached = to;
attached = e;
}
/*************************************************************************/
class TLoop {
public:
Alignment toAttached;
TElement* looped, *attached;
TLoop(TElement*, Alignment, TElement*);
};
TLoop::TLoop (TElement* l, Alignment to, TElement* e) {
looped = l;
toAttached = to;
attached = e;
}
/*************************************************************************/
class TNode {
friend class TNodeList;
public:
TNode(TElementList* = nil, TElementList* = nil);
TNode(Alignment, TElement*, Alignment = BottomLeft, TElement* = nil);
~TNode();
TNode* Copy();
void DeleteElements();
void Merge(TNode*);
void Exclude(TElement*);
boolean Includes(TElement*);
boolean Includes(Alignment&, TElement*);
boolean Overlaps(TNode*);
boolean Empty();
boolean Degenerate(TElement*&);
boolean Degenerate(Alignment&, TElement*&);
boolean Series(TElement*&, TElement*&);
boolean Stub(TElement*&);
boolean Loop(TElement*&);
void SetPosition(float);
float GetPosition();
private:
TElementList* lbElems, *rtElems;
float position;
TElementList* LeftBottomElements();
TElementList* RightTopElements();
void DeleteElements(TElementList*);
};
inline boolean TNode::Includes (TElement* e)
{ Alignment dummy; return Includes(dummy, e); }
inline boolean TNode::Empty () { return lbElems->Empty() && rtElems->Empty(); }
inline void TNode::SetPosition (float p) { position = p; }
inline float TNode::GetPosition () { return position; }
inline TElementList* TNode::LeftBottomElements () { return lbElems; }
inline TElementList* TNode::RightTopElements () { return rtElems; }
TNode::TNode (TElementList* l1, TElementList* l2) {
lbElems = l1;
rtElems = l2;
position = 0;
}
TNode::TNode (Alignment a1, TElement* e1, Alignment a2, TElement* e2) {
lbElems = new TElementList;
rtElems = new TElementList;
if (a1 == BottomLeft) {
rtElems->Append(new TElementList(e1));
} else {
lbElems->Append(new TElementList(e1));
}
if (e2 != nil) {
if (a2 == BottomLeft) {
rtElems->Append(new TElementList(e2));
} else {
lbElems->Append(new TElementList(e2));
}
position = 0;
}
}
TNode::~TNode () { delete lbElems; delete rtElems; }
void TNode::DeleteElements () {
register TElementList* t;
for (t = lbElems->First(); t != lbElems->End(); t = t->Next()) {
rtElems->Delete(t->GetElem());
}
DeleteElements(lbElems);
DeleteElements(rtElems);
}
void TNode::DeleteElements (TElementList* elems) {
register TElementList* t;
for (t = elems->First(); t != elems->End(); t = t->Next()) {
delete t->GetElem();
}
}
TNode* TNode::Copy () {
TNode* node = new TNode(lbElems->Copy(), rtElems->Copy());
node->SetPosition(GetPosition());
return node;
}
void TNode::Merge (TNode* n) {
register TElementList* nelems, *next;
TElementList* cur;
nelems = n->lbElems;
for (cur = nelems->First(); cur != nelems->End(); cur = next) {
next = cur->Next();
nelems->Remove(cur);
if (lbElems->Includes(cur->GetElem())) {
delete cur;
} else {
lbElems->Append(cur);
}
}
nelems = n->rtElems;
for (cur = nelems->First(); cur != nelems->End(); cur = next) {
next = cur->Next();
nelems->Remove(cur);
if (rtElems->Includes(cur->GetElem())) {
delete cur;
} else {
rtElems->Append(cur);
}
}
}
void TNode::Exclude (TElement* e) {
lbElems->Delete(e);
rtElems->Delete(e);
}
boolean TNode::Includes (Alignment& a, TElement* e) {
if (lbElems->Includes(e)) {
a = TopRight;
return true;
} else if (rtElems->Includes(e)) {
a = BottomLeft;
return true;
};
return false;
}
boolean TNode::Overlaps (TNode* n) {
register TElementList* nelems;
register TElementList* cur;
nelems = n->lbElems;
for (cur = nelems->First(); cur != nelems->End(); cur = cur->Next()) {
if (lbElems->Includes(cur->GetElem())) {
return true;
}
}
nelems = n->rtElems;
for (cur = nelems->First(); cur != nelems->End(); cur = cur->Next()) {
if (rtElems->Includes(cur->GetElem())) {
return true;
}
}
return false;
}
boolean TNode::Degenerate (TElement*& e) {
Alignment dummy;
return Degenerate(dummy, e);
}
boolean TNode::Degenerate (Alignment& a, TElement*& e) {
if (!lbElems->Empty() && rtElems->Empty()) {
if (lbElems->OnlyOne()) {
e = lbElems->First()->GetElem();
a = TopRight;
return true;
}
} else if (lbElems->Empty() && !rtElems->Empty()) {
if (rtElems->OnlyOne()) {
e = rtElems->First()->GetElem();
a = BottomLeft;
return true;
}
}
return false;
}
boolean TNode::Series (TElement*& e1, TElement*& e2) {
if (
!lbElems->Empty() && !rtElems->Empty() &&
lbElems->OnlyOne() && rtElems->OnlyOne()
) {
e1 = lbElems->First()->GetElem();
e2 = rtElems->First()->GetElem();
if (e1 != e2) {
return true;
}
}
return false;
}
boolean TNode::Stub (TElement*& e) {
if (lbElems->OnlyTwo() && rtElems->Empty()) {
e = lbElems->First()->GetElem();
return true;
} else if (lbElems->Empty() && rtElems->OnlyTwo()) {
e = rtElems->First()->GetElem();
return true;
}
return false;
}
boolean TNode::Loop (TElement*& e) {
register TElementList* cur;
for (cur = lbElems->First(); cur != lbElems->End(); cur = cur->Next()) {
e = cur->GetElem();
if (rtElems->Includes(e)) {
return true;
}
}
return false;
}
/*************************************************************************/
class TNodeList : public TList {
public:
TNodeList(TNode* = nil);
TNodeList* Copy();
void Include(Alignment, TElement*, Alignment = BottomLeft, TElement* =nil);
void Exclude(TElement*);
boolean Includes(TNode*);
void Nodes(TElement*, TNode*&, TNode*&);
TNode* Node(Alignment, TElement*);
TNode* OtherNode(TElement*, TNode*);
void AddMissingNodes(TElement*);
void Append(TNodeList*);
void Remove(TNodeList*);
TNodeList* First();
TNodeList* End();
TNodeList* Next();
TNodeList* Last();
void Delete(TNode*);
boolean Empty();
boolean OnlyOne();
TNode* GetNode();
boolean Degenerate(TElement*&);
boolean FoundTermination(TTermination*&, TNode*, TNode*);
boolean FoundSeries(TElement*&, TElement*&, TNode*, TNode*);
boolean FoundStub(TElement*&);
boolean FoundParallel(TElement*&, TElement*&);
boolean FoundCrossover(TElement*&);
boolean FoundLoop(TLoop*&);
void Reverse(TElement*);
void RemoveTermination(TTermination*);
void RemoveSeries(TElement*, TElement*, TElement*);
void RemoveParallel(TElement*, TElement*, TElement*);
void RemoveLoop(TLoop*);
void ReplaceTermination(TTermination*);
void ReplaceSeries(TElement*, TElement*, TElement*);
void ReplaceParallel(TElement*, TElement*, TElement*);
void ReplaceLoop(TLoop*);
void ApplyToTermination(TTermination*);
void ApplyToSeries(TElement*, TElement*, TElement*);
void ApplyToParallel(TElement*, TElement*, TElement*);
void ApplyToLoop(TLoop*);
void FindElements(Interactor*, TElement*&, TElement*&);
void FindElement(TGlue*, TElement*&);
private:
boolean FoundParallel(TNode*, TElement*&, TElement*&);
boolean FoundParallel(TElementList*, TNode*, TElement*&, TElement*&);
boolean FoundCrossover(TNode*, TElement*&);
void FindElements(TElementList*, Interactor*, TElement*&, TElement*&);
void FindElement(TElementList*, TGlue*, TElement*&);
Alignment Inverse(Alignment);
void GetElemOtherThan(TElement*, TNode*, Alignment&, TElement*&);
};
inline boolean TNodeList::Includes (TNode* t) { return TList::Find(t) != nil; }
inline TNode* TNodeList::GetNode () { return (TNode*) GetContents(); }
inline boolean TNodeList::FoundParallel (
TNode* n, TElement*& e1, TElement*& e2
) {
return
FoundParallel(n->LeftBottomElements(), n, e1, e2) ||
FoundParallel(n->RightTopElements(), n, e1, e2);
}
inline void TNodeList::Append (TNodeList* t) { TList::Append(t); }
inline void TNodeList::Remove (TNodeList* t) { TList::Remove(t); }
inline void TNodeList::Delete (TNode* o) { TList::Delete(o); }
inline TNodeList* TNodeList::First () { return (TNodeList*) TList::First(); }
inline TNodeList* TNodeList::End () { return (TNodeList*) TList::End(); }
inline TNodeList* TNodeList::Next () { return (TNodeList*) TList::Next(); }
inline TNodeList* TNodeList::Last () { return (TNodeList*) TList::Last(); }
inline boolean TNodeList::Empty () { return TList::Empty(); }
inline boolean TNodeList::OnlyOne () { return !Empty() && First() == Last(); }
inline Alignment TNodeList::Inverse (Alignment a)
{ return (a == BottomLeft) ? TopRight : BottomLeft; }
TNodeList::TNodeList (TNode* o) : (o) { }
TNodeList* TNodeList::Copy () {
register TNodeList* t;
TNodeList* newlist = new TNodeList;
TNode* node;
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
newlist->Append(new TNodeList(node->Copy()));
}
return newlist;
}
void TNodeList::Include (
Alignment a1, TElement* e1, Alignment a2, TElement* e2
) {
register TNodeList* t;
TNode pass1(a1, e1, a2, e2);
TNode* node, *pass2;
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
if (node->Overlaps(&pass1)) {
node->Merge(&pass1);
pass2 = node;
break;
}
}
if (t == End()) {
Append(new TNodeList(pass1.Copy()));
} else {
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
if (node != pass2 && node->Overlaps(pass2)) {
node->Merge(pass2);
Delete(pass2);
delete pass2;
break;
}
}
}
}
void TNodeList::Exclude (TElement* e) {
register TNodeList* t, *next;
TNode* node;
int n = 0;
for (t = First(); t != End() && n <= 1; t = next) {
next = t->Next();
node = t->GetNode();
if (node->Includes(e)) {
++n;
node->Exclude(e);
if (node->Empty()) {
Remove(t);
delete t;
}
}
}
}
boolean TNodeList::Degenerate (TElement*& e) {
TElement* alt;
TNode* nfirst = First()->GetNode();
TNode* nlast = Last()->GetNode();
return
First()->Next() == Last() &&
nfirst->Degenerate(e) && nlast->Degenerate(alt) &&
e == alt;
}
boolean TNodeList::FoundTermination (
TTermination*& term, TNode* lbMagic, TNode* rtMagic
) {
register TNodeList* t;
TElement* dangling, *attached;
Alignment a, toAttached;
TNode* degenTest, *attachment;
for (t = First(); t != End(); t = t->Next()) {
degenTest = t->GetNode();
if (
degenTest != lbMagic && degenTest != rtMagic &&
degenTest->Degenerate(a, dangling)
) {
attachment = OtherNode(dangling, degenTest);
GetElemOtherThan(dangling, attachment, toAttached, attached);
if (attached != nil) {
term = new TTermination(a, dangling, toAttached, attached);
return true;
}
}
}
return false;
}
boolean TNodeList::FoundSeries (
TElement*& e1, TElement*& e2, TNode* lbMagic, TNode* rtMagic
) {
register TNodeList* t;
TNode* node;
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
if (node != lbMagic && node != rtMagic && node->Series(e1, e2)) {
return true;
}
}
return false;
}
boolean TNodeList::FoundStub (TElement*& e) {
register TNodeList* t;
TNode* node;
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
if (node->Stub(e)) {
return true;
}
}
return false;
}
boolean TNodeList::FoundParallel (TElement*& e1, TElement*& e2) {
register TNodeList* t;
TNode* node;
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
if (FoundParallel(node, e1, e2)) {
return true;
}
}
return false;
}
boolean TNodeList::FoundParallel (
TElementList* elems, TNode* n, TElement*& e1, TElement*& e2
) {
register TElementList* cur, *test;
TNode* ncur, *ntest;
for (cur = elems->First(); cur != elems->End(); cur = cur->Next()) {
e1 = cur->GetElem();
ncur = OtherNode(e1, n);
if (ncur != nil) {
for (
test = cur->Next();
test != elems->End();
test = test->Next()
) {
e2 = test->GetElem();
ntest = OtherNode(e2, n);
if (ntest == ncur) {
return true;
}
}
}
}
return false;
}
boolean TNodeList::FoundCrossover (TElement*& e) {
register TNodeList* t;
TNode* node;
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
if (FoundCrossover(node, e)) {
return true;
}
}
return false;
}
boolean TNodeList::FoundLoop (TLoop*& loop) {
register TNodeList* t;
TElement* looped, *attached;
Alignment toAttached;
TNode* loopTest;
for (t = First(); t != End(); t = t->Next()) {
loopTest = t->GetNode();
if (loopTest->Loop(looped)) {
GetElemOtherThan(looped, loopTest, toAttached, attached);
loop = new TLoop(looped, toAttached, attached);
return true;
}
}
return false;
}
boolean TNodeList::FoundCrossover (TNode* n, TElement*& e1) {
TElementList* lbElems, *rtElems, *cur, *test;
TElement* e2;
TNode* ncur, *ntest;
lbElems = n->LeftBottomElements();
rtElems = n->RightTopElements();
for (cur = lbElems->First(); cur != lbElems->End(); cur = cur->Next()) {
e1 = cur->GetElem();
ncur = OtherNode(e1, n);
if (ncur != nil) {
for (
test = rtElems->First();
test != rtElems->End();
test = test->Next()
) {
e2 = test->GetElem();
ntest = OtherNode(e2, n);
if (ntest == ncur) {
return true;
}
}
}
}
return false;
}
TNode* TNodeList::OtherNode (TElement* e, TNode* n) {
register TNodeList* t;
TNode* ntest;
for (t = First(); t != End(); t = t->Next()) {
ntest = t->GetNode();
if (ntest != n && ntest->Includes(e)) {
return ntest;
}
}
return nil;
}
void TNodeList::RemoveTermination (TTermination* t) {
TNode* degen, *attachment = Node(t->toAttached, t->attached);
attachment->Exclude(t->dangling);
degen = OtherNode(t->dangling, attachment);
Delete(degen);
delete degen;
}
void TNodeList::RemoveSeries (TElement* equiv, TElement* e1, TElement* e2) {
TNode* n1lb, *n2lb, *n2rt;
TNode eqlb(BottomLeft, equiv);
TNode eqrt(TopRight, equiv);
Nodes(e2, n2lb, n2rt);
n1lb = OtherNode(e1, n2lb);
if (n1lb == nil) { // check for ends tied together
n1lb = n2rt;
} else if (n2rt == nil) {
n2rt = n1lb;
}
n1lb->Merge(&eqlb);
n2rt->Merge(&eqrt);
n1lb->Exclude(e1);
n2rt->Exclude(e2);
Delete(n2lb);
delete n2lb;
}
void TNodeList::Reverse (TElement* e) {
TNode* nlb, *nrt;
TNode elb(BottomLeft, e);
TNode ert(TopRight, e);
Nodes(e, nlb, nrt);
nlb->Exclude(e);
nrt->Exclude(e);
nlb->Merge(&ert);
nrt->Merge(&elb);
e->Reverse();
}
void TNodeList::RemoveParallel (TElement* equiv, TElement* e1, TElement* e2) {
TNode* n1lb, *n1rt;
TNode eqlb(BottomLeft, equiv);
TNode eqrt(TopRight, equiv);
Nodes(e1, n1lb, n1rt);
n1lb->Merge(&eqlb);
n1rt->Merge(&eqrt);
n1lb->Exclude(e1);
n1lb->Exclude(e2);
n1rt->Exclude(e1);
n1rt->Exclude(e2);
}
void TNodeList::RemoveLoop (TLoop* l) {
TNode* attachment;
if (l->attached == nil) { // isolated loop
attachment = OtherNode(l->looped, nil);
Delete(attachment);
delete attachment;
} else {
attachment = Node(l->toAttached, l->attached);
attachment->Exclude(l->looped);
}
}
void TNodeList::ReplaceTermination (TTermination* t) {
TNode* degen, *attachment = Node(t->toAttached, t->attached);
float apos;
Alignment a = Inverse(t->alignment);
TElement* e = t->dangling;
TNode temp(a, e);
attachment->Merge(&temp);
apos = attachment->GetPosition();
degen = new TNode(t->alignment, t->dangling);
if (t->alignment == BottomLeft) {
degen->SetPosition(apos - t->dangling->nat - t->dangling->sigma);
} else {
degen->SetPosition(apos + t->dangling->nat + t->dangling->sigma);
}
Append(new TNodeList(degen));
}
void TNodeList::ReplaceSeries (TElement* equiv, TElement* e1, TElement* e2) {
TNode* eqlb, *eqrt, *nctr;
Nodes(equiv, eqlb, eqrt);
if (eqlb == nil) { // check for ends tied together
eqlb = eqrt;
} else if (eqrt == nil) {
eqrt = eqlb;
}
TNode nlb(BottomLeft, e1);
TNode nrt(TopRight, e2);
eqlb->Merge(&nlb);
eqrt->Merge(&nrt);
eqlb->Exclude(equiv);
eqrt->Exclude(equiv);
nctr = new TNode(TopRight, e1, BottomLeft, e2);
nctr->SetPosition(e2->pos);
Append(new TNodeList(nctr));
}
void TNodeList::ReplaceParallel (
TElement* equiv, TElement* e1, TElement* e2
) {
TNode* eqlb, *eqrt;
TNode nlb(BottomLeft, e1, BottomLeft, e2);
TNode nrt(TopRight, e1, TopRight, e2);
Nodes(equiv, eqlb, eqrt);
eqlb->Merge(&nlb);
eqrt->Merge(&nrt);
eqlb->Exclude(equiv);
eqrt->Exclude(equiv);
}
void TNodeList::ReplaceLoop (TLoop* l) {
TNode* attachment;
if (l->attached == nil) {
attachment = new TNode(BottomLeft, l->looped, TopRight, l->looped);
Append(new TNodeList(attachment));
} else {
attachment = Node(l->toAttached, l->attached);
TNode node(BottomLeft, l->looped, TopRight, l->looped);
attachment->Merge(&node);
}
}
void TNodeList::FindElements (
Interactor* i, TElement*& lbElem, TElement*& rtElem
) {
register TNodeList* nl;
TNode* node;
TElementList* el;
lbElem = rtElem = nil;
for (
nl = First();
nl != End() && (lbElem == nil || rtElem == nil);
nl = nl->Next()
) {
node = nl->GetNode();
el = node->LeftBottomElements();
FindElements(el, i, lbElem, rtElem);
if (lbElem == nil || rtElem == nil) {
el = node->RightTopElements();
FindElements(el, i, lbElem, rtElem);
}
}
}
void TNodeList::FindElement (TGlue* tg, TElement*& elem) {
register TNodeList* nl;
TNode* node;
TElementList* el;
elem = nil;
for (nl = First(); nl != End() && elem == nil; nl = nl->Next()) {
node = nl->GetNode();
el = node->LeftBottomElements();
FindElement(el, tg, elem);
if (elem == nil) {
el = node->RightTopElements();
FindElement(el, tg, elem);
}
}
}
void TNodeList::FindElements (
TElementList* el, Interactor* i, TElement*& lbElem, TElement*& rtElem
) {
register TElementList* cur;
TElement* test;
for (
cur = el->First();
cur != el->End() && (lbElem == nil || rtElem == nil);
cur = cur->Next()
) {
test = cur->GetElem();
if (test->owner == i) {
if (test->leftBotHalf) {
lbElem = test;
} else {
rtElem = test;
}
}
}
}
void TNodeList::FindElement (TElementList* el, TGlue* tg, TElement*& elem) {
register TElementList* cur;
TElement* test;
for (cur = el->First(); cur != el->End(); cur = cur->Next()) {
test = cur->GetElem();
if (test->tglue == tg) {
elem = test;
return;
}
}
}
void TNodeList::Nodes (TElement* e, TNode*& nlb, TNode*& nrt) {
register TNodeList* t;
TNode* node;
Alignment a;
nlb = nrt = nil;
for (t = First(); t != End() && (nlb==nil || nrt==nil); t = t->Next()) {
node = t->GetNode();
if (node->Includes(a, e)) {
if (a == BottomLeft) { /* node is below/left of element */
nlb = node;
} else {
nrt = node;
}
}
}
}
TNode* TNodeList::Node (Alignment a, TElement* e) {
register TNodeList* t;
TNode* node;
Alignment test;
for (t = First(); t != End(); t = t->Next()) {
node = t->GetNode();
if (node->Includes(test, e) && test == a) {
return node;
}
}
}
void TNodeList::AddMissingNodes (TElement* e) {
TNode* nlb, *nrt;
TNodeList* lb, *rt;
Nodes(e, nlb, nrt);
if (nlb == nil) {
nlb = new TNode(BottomLeft, e);
nlb->SetPosition(e->pos);
lb = new TNodeList(nlb);
Append(lb);
}
if (nrt == nil) {
nrt = new TNode(TopRight, e);
nrt->SetPosition(e->pos + e->nat + e->sigma);
rt = new TNodeList(nrt);
Append(rt);
}
}
void TNodeList::GetElemOtherThan (
TElement* avoid, TNode* n, Alignment& a, TElement*& e
) {
register TElementList* cur;
TElementList* lbElems, *rtElems;
lbElems = n->LeftBottomElements();
rtElems = n->RightTopElements();
for (cur = lbElems->First(); cur != lbElems->End(); cur = cur->Next()) {
e = cur->GetElem();
if (e != avoid) {
a = TopRight;
return;
}
}
for (cur = rtElems->First(); cur != rtElems->End(); cur = cur->Next()) {
e = cur->GetElem();
if (e != avoid) {
a = BottomLeft;
return;
}
}
e = nil;
}
void TNodeList::ApplyToTermination (TTermination* t) {
TNode* n = Node(t->toAttached, t->attached);
if (t->alignment == BottomLeft) {
t->dangling->pos = n->GetPosition() - t->dangling->nat;
} else {
t->dangling->pos = n->GetPosition();
}
t->dangling->sigma = 0;
}
void TNodeList::ApplyToSeries (TElement* equiv, TElement* e1, TElement* e2) {
float d = equiv->nat + equiv->sigma - e1->nat - e2->nat;
float s1, s2;
if (d < 0) {
s1 = e1->shrink;
s2 = e2->shrink;
} else {
s1 = e1->stretch;
s2 = e2->stretch;
}
if (s1 == 0 && s2 == 0) {
e1->sigma = e2->sigma = 0;
} else {
e1->sigma = equiv->sigma * s1 / (s1 + s2);
}
e1->Limit();
e2->sigma = equiv->sigma - e1->sigma;
e2->Limit();
e1->pos = equiv->pos;
e2->pos = e1->pos + e1->nat + e1->sigma;
}
void TNodeList::ApplyToParallel (TElement* equiv, TElement* e1, TElement* e2) {
e1->pos = e2->pos = equiv->pos;
e1->sigma = equiv->nat + equiv->sigma - e1->nat;
e2->sigma = equiv->nat + equiv->sigma - e2->nat;
e1->Limit();
e2->Limit();
}
void TNodeList::ApplyToLoop (TLoop* l) {
TNode* n = Node(l->toAttached, l->attached);
l->looped->pos = n->GetPosition();
l->looped->sigma = -l->looped->shrink;
}
/*************************************************************************/
class TSolver {
public:
TSolver(Tray*, Interactor*);
~TSolver();
void AddAlignment(Alignment, Interactor*, TGlue* = nil);
void AddAlignment(
Alignment, Interactor*, Alignment, Interactor*, TGlue* = nil
);
void DeleteAlignmentsTo(Interactor*);
void SetShape(Interactor*);
void Solve(int, int);
void CalcShape(Shape*);
void GetPlacement(Interactor*, Coord&, Coord&, Coord&, Coord&);
private:
TNodeList* hnodes, *vnodes;
TNode* lmagic, *rmagic, *bmagic, *tmagic;
Tray* tray;
Interactor* background;
Interactor* BgFilter(Interactor*);
void Solve(
TNodeList*, TNode*, TNode*, int size, int& nat, int& shr, int& str
);
void GetPlacement(TNodeList*, Interactor*, int, Coord&, Coord&);
void HOrder(Alignment, Interactor*&, Interactor*&);
void VOrder(Alignment, Interactor*&, Interactor*&);
void HConvert(Interactor*, TElement*&, TElement*&);
void HConvert(TGlue*, TElement*&);
void VConvert(Interactor*, TElement*&, TElement*&);
void VConvert(TGlue*, TElement*&);
void HAddAlignment(
Alignment, TElement*, TElement*, Alignment, TElement*, TElement*,
TElement*
);
void VAddAlignment(
Alignment, TElement*, TElement*, Alignment, TElement*, TElement*,
TElement*
);
void Include(
TNodeList*, Alignment, TElement*, Alignment, TElement*, TElement*
);
void TrayNodes(TNodeList*, TNode*&, TNode*&);
void UpdateMagicNodes();
void DeleteDanglingGlue(TNodeList*, TNode*);
void DeleteNodesAndElements(TNodeList*);
};
TSolver::TSolver (Tray* t, Interactor* bg) {
hnodes = new TNodeList;
vnodes = new TNodeList;
tray = t;
background = bg;
lmagic = rmagic = bmagic = tmagic = nil;
}
TSolver::~TSolver () {
DeleteNodesAndElements(hnodes);
DeleteNodesAndElements(vnodes);
delete hnodes;
delete vnodes;
}
void TSolver::DeleteNodesAndElements (TNodeList* nodes) {
TNode* merged;
register TNodeList* t = nodes->First();
if (t == nodes->End()) {
return;
}
merged = t->GetNode();
for (t = t->Next(); t != nodes->End(); t = t->Next()) {
TNode* doomed = t->GetNode();
merged->Merge(doomed);
delete doomed;
}
merged->DeleteElements();
delete merged;
}
inline boolean HAlignment (Alignment a) {
return a != Bottom && a != VertCenter && a != Top;
}
inline boolean VAlignment (Alignment a) {
return a != Left && a != HorizCenter && a != Right;
}
void TSolver::AddAlignment (
Alignment a1, Interactor* i1, Alignment a2, Interactor* i2, TGlue* tg
) {
TElement* e1l, *e1r, *e2l, *e2r, *e3;
i1 = BgFilter(i1);
i2 = BgFilter(i2);
if (HAlignment(a1) && HAlignment(a2)) {
HConvert(i1, e1l, e1r);
HConvert(i2, e2l, e2r);
HConvert(tg, e3);
HAddAlignment(a1, e1l, e1r, a2, e2l, e2r, e3);
}
if (VAlignment(a1) && VAlignment(a2)) {
VConvert(i1, e1l, e1r);
VConvert(i2, e2l, e2r);
VConvert(tg, e3);
VAddAlignment(a1, e1l, e1r, a2, e2l, e2r, e3);
}
UpdateMagicNodes();
}
void TSolver::AddAlignment (Alignment a, Interactor* i, TGlue* tg) {
TElement* e1l, *e1r, *e2l, *e2r, *e3;
Interactor* i1 = i;
Interactor* i2 = tray;
if (i == background || i == tray) {
return;
}
if (HAlignment(a)) {
HOrder(a, i1, i2);
HConvert(i1, e1l, e1r);
HConvert(i2, e2l, e2r);
HConvert(tg, e3);
HAddAlignment(a, e1l, e1r, a, e2l, e2r, e3);
}
if (VAlignment(a)) {
VOrder(a, i1, i2);
VConvert(i1, e1l, e1r);
VConvert(i2, e2l, e2r);
VConvert(tg, e3);
VAddAlignment(a, e1l, e1r, a, e2l, e2r, e3);
}
UpdateMagicNodes();
}
void TSolver::HOrder (Alignment a, Interactor*& i1, Interactor*& i2) {
Interactor* i = (i1 == tray) ? i2 : i1;
if (a == BottomRight || a == CenterRight || a == TopRight || a == Right) {
i1 = i;
i2 = tray;
} else {
i1 = tray;
i2 = i;
}
}
void TSolver::VOrder (Alignment a, Interactor*& i1, Interactor*& i2) {
Interactor* i = (i1 == tray) ? i2 : i1;
if (a == TopLeft || a == TopCenter || a == TopRight || a == Top) {
i1 = i;
i2 = tray;
} else {
i1 = tray;
i2 = i;
}
}
void TSolver::DeleteAlignmentsTo (Interactor* i) {
TElement* e1, *e2;
TNode* lb, *rt;
i = BgFilter(i);
hnodes->FindElements(i, e1, e2);
if (e1 != nil) {
lb = hnodes->Node(BottomLeft, e1);
rt = hnodes->Node(TopRight, e2);
hnodes->Exclude(e1);
hnodes->Exclude(e2);
delete e1;
delete e2;
DeleteDanglingGlue(hnodes, lb);
DeleteDanglingGlue(hnodes, rt);
}
vnodes->FindElements(i, e1, e2);
if (e1 != nil) {
lb = vnodes->Node(BottomLeft, e1);
rt = vnodes->Node(TopRight, e2);
vnodes->Exclude(e1);
vnodes->Exclude(e2);
delete e1;
delete e2;
DeleteDanglingGlue(vnodes, lb);
DeleteDanglingGlue(vnodes, rt);
}
}
void TSolver::SetShape (Interactor* i) {
TElement* lbElem, *rtElem;
i = BgFilter(i);
hnodes->FindElements(i, lbElem, rtElem);
if (lbElem == nil) {
return;
}
lbElem->HSetShape();
rtElem->HSetShape();
vnodes->FindElements(i, lbElem, rtElem);
if (lbElem == nil) {
return;
}
lbElem->VSetShape();
rtElem->VSetShape();
}
void TSolver::Solve (int w, int h) {
int dummy;
if (lmagic != nil) {
lmagic->SetPosition(0);
rmagic->SetPosition(w);
Solve(hnodes, lmagic, rmagic, w, dummy, dummy, dummy);
}
if (bmagic != nil) {
bmagic->SetPosition(0);
tmagic->SetPosition(h);
Solve(vnodes, bmagic, tmagic, h, dummy, dummy, dummy);
}
}
void TSolver::CalcShape (Shape* s) {
TElement* ltray, *rtray, *btray, *ttray;
hnodes->FindElements(tray, ltray, rtray);
vnodes->FindElements(tray, btray, ttray);
if (ltray != nil && lmagic != nil) {
ltray->combinable = rtray->combinable = false;
Solve(hnodes, lmagic, rmagic, 0, s->width, s->hshrink, s->hstretch);
ltray->combinable = rtray->combinable = true;
}
if (btray != nil && bmagic != nil) {
btray->combinable = ttray->combinable = false;
Solve(vnodes, bmagic, tmagic, 0, s->height, s->vshrink, s->vstretch);
btray->combinable = ttray->combinable = true;
}
}
void TSolver::GetPlacement (
Interactor* i, Coord& l, Coord& b, Coord& r, Coord& t
) {
Shape* s = i->GetShape();
GetPlacement(hnodes, i, s->width, l, r);
GetPlacement(vnodes, i, s->height, b, t);
}
void TSolver::GetPlacement (
TNodeList* nodes, Interactor* i, int dfault, Coord& lb, Coord& rt
) {
TElement* lbElem, *rtElem;
nodes->FindElements(i, lbElem, rtElem);
if (lbElem == nil) {
lb = 0;
rt = dfault - 1;
} else {
lb = round(lbElem->pos);
rt = round(
lbElem->pos + lbElem->nat + lbElem->sigma +
rtElem->nat + rtElem->sigma - 1
);
}
}
void TSolver::Solve (
TNodeList* nodes, TNode* lbMagic, TNode* rtMagic, int size,
int& nat, int& shr, int& str
) {
TElement* e1, *e2, *e3;
TTermination* t;
TLoop* l;
TNode* n;
if (nodes->Empty()) {
/* no alignments; do nothing */
} else if (nodes->Degenerate(e1)) {
nat = round(e1->nat);
shr = round(e1->shrink);
str = round(e1->stretch);
e1->pos = (lbMagic == nil) ? 0 : lbMagic->GetPosition();
e1->sigma = (rtMagic == nil) ? e1->nat : size - round(e1->nat);
e1->Limit();
} else if (nodes->FoundSeries(e1, e2, lbMagic, rtMagic)) {
e3 = e1->Series(e2);
nodes->RemoveSeries(e3, e1, e2);
Solve(nodes, lbMagic, rtMagic, size, nat, shr, str);
nodes->ApplyToSeries(e3, e1, e2);
nodes->ReplaceSeries(e3, e1, e2);
delete e3;
} else if (nodes->FoundParallel(e1, e2)) {
e3 = e1->Parallel(e2);
nodes->RemoveParallel(e3, e1, e2);
Solve(nodes, lbMagic, rtMagic, size, nat, shr, str);
nodes->ApplyToParallel(e3, e1, e2);
nodes->ReplaceParallel(e3, e1, e2);
delete e3;
} else if (nodes->FoundTermination(t, lbMagic, rtMagic)) {
nodes->RemoveTermination(t);
Solve(nodes, lbMagic, rtMagic, size, nat, shr, str);
nodes->ApplyToTermination(t);
nodes->ReplaceTermination(t);
delete t;
} else if (nodes->FoundStub(e1) || nodes->FoundCrossover(e1)) {
nodes->Reverse(e1);
Solve(nodes, lbMagic, rtMagic, size, nat, shr, str);
nodes->Reverse(e1);
} else if (nodes->FoundLoop(l)) {
nodes->RemoveLoop(l);
Solve(nodes, lbMagic, rtMagic, size, nat, shr, str);
nodes->ApplyToLoop(l);
nodes->ReplaceLoop(l);
delete l;
} else if (nodes->OnlyOne()) {
n = nodes->First()->GetNode();
if (n != lbMagic && n != rtMagic) {
n->SetPosition(0);
}
nat = str = shr = 0;
}
}
void TSolver::HConvert (Interactor* i, TElement*& el, TElement*& er) {
if (i == nil) {
el = er = nil;
} else {
hnodes->FindElements(i, el, er);
if (el == nil) {
el = new TElement(i);
el->combinable = true;
el->leftBotHalf = true;
el->HSetShape();
er = new TElement(i);
er->combinable = true;
er->leftBotHalf = false;
er->HSetShape();
hnodes->Include(TopRight, el, BottomLeft, er);
}
}
}
void TSolver::HConvert (TGlue* tg, TElement*& e) {
if (tg == nil) {
e = nil;
} else {
hnodes->FindElement(tg, e);
if (e == nil) {
e = new TElement(tg);
e->combinable = true;
e->leftBotHalf = true;
e->HSetShape();
}
}
}
void TSolver::VConvert (Interactor* i, TElement*& eb, TElement*& et) {
if (i == nil) {
eb = et = nil;
} else {
vnodes->FindElements(i, eb, et);
if (eb == nil) {
eb = new TElement(i);
eb->combinable = true;
eb->leftBotHalf = true;
eb->VSetShape();
et = new TElement(i);
et->combinable = true;
et->leftBotHalf = false;
et->VSetShape();
vnodes->Include(TopRight, eb, BottomLeft, et);
}
}
}
void TSolver::VConvert (TGlue* tg, TElement*& e) {
if (tg == nil) {
e = nil;
} else {
vnodes->FindElement(tg, e);
if (e == nil) {
e = new TElement(tg);
e->combinable = true;
e->leftBotHalf = true;
e->VSetShape();
}
}
}
void TSolver::HAddAlignment (
Alignment a1, TElement* e1l, TElement* e1r,
Alignment a2, TElement* e2l, TElement* e2r,
TElement* tg
) {
TElement* e1, *e2;
Alignment na1, na2;
switch (a1) {
case TopLeft:
case CenterLeft:
case BottomLeft:
case Left:
e1 = e1l;
na1 = BottomLeft;
break;
case TopCenter:
case Center:
case BottomCenter:
case HorizCenter:
e1 = e1l;
na1 = TopRight;
break;
case TopRight:
case CenterRight:
case BottomRight:
case Right:
e1 = e1r;
na1 = TopRight;
break;
}
switch (a2) {
case TopLeft:
case CenterLeft:
case BottomLeft:
case Left:
e2 = e2l;
na2 = BottomLeft;
break;
case TopCenter:
case Center:
case BottomCenter:
case HorizCenter:
e2 = e2l;
na2 = TopRight;
break;
case TopRight:
case CenterRight:
case BottomRight:
case Right:
e2 = e2r;
na2 = TopRight;
break;
}
hnodes->AddMissingNodes(e1l);
hnodes->AddMissingNodes(e1r);
hnodes->AddMissingNodes(e2l);
hnodes->AddMissingNodes(e2r);
Include(hnodes, na1, e1, na2, e2, tg);
}
void TSolver::VAddAlignment (
Alignment a1, TElement* e1b, TElement* e1t,
Alignment a2, TElement* e2b, TElement* e2t,
TElement* tg
) {
TElement* e1, *e2;
Alignment na1, na2;
switch (a1) {
case BottomLeft:
case BottomCenter:
case BottomRight:
case Bottom:
e1 = e1b;
na1 = BottomLeft;
break;
case CenterLeft:
case Center:
case CenterRight:
case VertCenter:
e1 = e1b;
na1 = TopRight;
break;
case TopLeft:
case TopCenter:
case TopRight:
case Top:
e1 = e1t;
na1 = TopRight;
break;
}
switch (a2) {
case BottomLeft:
case BottomCenter:
case BottomRight:
case Bottom:
e2 = e2b;
na2 = BottomLeft;
break;
case CenterLeft:
case Center:
case CenterRight:
case VertCenter:
e2 = e2b;
na2 = TopRight;
break;
case TopLeft:
case TopCenter:
case TopRight:
case Top:
e2 = e2t;
na2 = TopRight;
break;
}
vnodes->AddMissingNodes(e1b);
vnodes->AddMissingNodes(e1t);
vnodes->AddMissingNodes(e2b);
vnodes->AddMissingNodes(e2t);
Include(vnodes, na1, e1, na2, e2, tg);
}
void TSolver::Include (
TNodeList* nodes,
Alignment na1, TElement* e1, Alignment na2, TElement* e2, TElement* tg
) {
if (e1->owner == e2->owner && na1 == na2) {
/* aligned a node to itself; do nothing */
} else if (tg == nil) {
nodes->Include(na1, e1, na2, e2);
} else if (na1 == BottomLeft && na2 == TopRight) {
nodes->Include(BottomLeft, e1, TopRight, tg);
nodes->Include(TopRight, e2, BottomLeft, tg);
} else {
nodes->Include(na1, e1, BottomLeft, tg);
nodes->Include(na2, e2, TopRight, tg);
}
}
void TSolver::TrayNodes (TNodeList* nodes, TNode*& nlb, TNode*& nrt) {
TNode *ctr;
TElement* elb, *ert;
nodes->FindElements(tray, elb, ert);
if (elb == nil) {
nlb = nrt = nil;
} else {
nodes->Nodes(elb, nlb, ctr);
nrt = nodes->OtherNode(ert, ctr);
}
}
void TSolver::UpdateMagicNodes () {
TrayNodes(hnodes, lmagic, rmagic);
TrayNodes(vnodes, bmagic, tmagic);
}
void TSolver::DeleteDanglingGlue (TNodeList* nodes, TNode* n) {
TElement* e;
if (n->Degenerate(e) && e->tglue != nil) {
nodes->Exclude(e);
delete e;
}
}
Interactor* TSolver::BgFilter (Interactor* i) {
return (i == background) ? tray : i;
}
/*************************************************************************/
class TrayElement {
public:
Interactor* child;
boolean visible;
TrayElement* next;
};
/*************************************************************************/
TGlue::TGlue (int w, int h, int hstr, int vstr) {
shape = new Shape;
shape->width = w;
shape->height = h;
shape->hshrink = 0;
shape->hstretch = hstr;
shape->vshrink = 0;
shape->vstretch = vstr;
}
TGlue::TGlue (int w, int h, int hshr, int hstr, int vshr, int vstr) {
shape = new Shape;
shape->width = w;
shape->height = h;
shape->hshrink = hshr;
shape->hstretch = hstr;
shape->vshrink = vshr;
shape->vstretch = vstr;
}
TGlue::~TGlue () {
delete shape;
}
/*************************************************************************/
inline boolean Tray::TrayOrBg (Interactor* i) { return i == this || i == bg; }
Tray::Tray (Interactor* b) {
Init(b);
}
Tray::Tray (const char* name, Interactor* b) {
SetInstance(name);
Init(b);
}
void Tray::Init (Interactor* b) {
SetClassName("Tray");
nelements = 0;
head = nil;
tail = nil;
bg = b;
tsolver = new TSolver(this, bg);
}
Tray::~Tray () {
register TrayElement* e, *next;
delete tsolver;
for (e = head; e != nil; e = next) {
next = e->next;
delete e->child;
delete e;
}
if (bg != nil) {
delete bg;
}
}
void Tray::ComponentBounds (int& w, int& h) {
register TrayElement* e, *next;
Shape* s;
w = h = 0;
for (e = head; e != nil; e = next) {
next = e->next;
s = e->child->GetShape();
w = max(w, s->width);
h = max(h, s->height);
}
}
void Tray::CalcShape () {
int w, h;
if (bg == nil) {
ComponentBounds(w, h);
tsolver->CalcShape(shape);
shape->width = max(shape->width, w);
shape->height = max(shape->height, h);
} else {
*shape = *bg->GetShape();
}
tsolver->SetShape(this);
}
void Tray::Reconfig () {
register TrayElement* e;
for (e = head; e != nil; e = e->next) {
tsolver->SetShape(e->child);
}
CalcShape();
}
void Tray::DoInsert (Interactor* i, boolean, Coord&, Coord&) {
++nelements;
register TrayElement* e = new TrayElement;
e->child = i;
e->next = nil;
if (head == nil) {
head = e;
tail = e;
} else {
tail->next = e;
tail = e;
}
}
void Tray::DoChange (Interactor* i) {
tsolver->SetShape(i);
CalcShape();
}
void Tray::DoRemove (Interactor* i) {
register TrayElement* e, * prev;
if (i == bg) {
bg = nil;
tsolver->DeleteAlignmentsTo(i);
} else {
--nelements;
prev = nil;
for (e = head; e != nil; e = e->next) {
if (e->child == i) {
if (prev == nil) {
head = e->next;
} else {
prev->next = e->next;
}
if (e == tail) {
tail = prev;
}
delete e;
tsolver->DeleteAlignmentsTo(i);
break;
}
prev = e;
}
}
}
void Tray::Resize () {
register TrayElement* e;
canvas->SetBackground(output->GetBgColor());
if (bg != nil) {
Place(bg, 0, 0, xmax, ymax);
}
for (e = head; e != nil; e = e->next) {
tsolver->SetShape(e->child);
}
tsolver->Solve(xmax+1, ymax+1);
for (e = head; e != nil; e = e->next) {
PlaceElement(e);
}
}
boolean Tray::AlreadyInserted (Interactor* i) {
register TrayElement* e;
if (i == this || i == bg) {
return true;
}
for (e = head; e != nil; e = e->next) {
if (e->child == i) {
return true;
}
}
return false;
}
void Tray::PlaceElement (TrayElement* e) {
Coord l, b, r, t, tmp;
tsolver->GetPlacement(e->child, l, b, r, t);
if (
r > 0 && l < xmax && t > 0 && b < ymax &&
r - l != -1 && t - b != -1
) {
e->visible = true;
tmp = min(l, r);
r = max(l, r);
l = tmp;
tmp = min(b, t);
t = max(b, t);
b = tmp;
Place(e->child, l, b, r, t);
} else {
e->visible = false;
}
}
void Tray::Draw () {
register TrayElement* e;
if (bg != nil) {
bg->Draw();
}
for (e = head; e != nil; e = e->next) {
if (e->visible) {
e->child->Draw();
}
}
}
void Tray::Reshape (Shape& s) {
*shape = s;
Scene* p = Parent();
if (p != nil) {
p->Change(this);
}
}
void Tray::GetComponents (Interactor** c, int nc, Interactor**& a, int& n) {
register TrayElement* e;
register Interactor** ap;
n = nelements;
if (bg != nil) {
++n;
}
a = (n <= nc) ? c : new Interactor*[n];
ap = a;
for (e = head; e != nil; e = e->next) {
*ap++ = e->child;
}
if (bg != nil) {
*ap = bg;
}
}
void Tray::Align (
Alignment a1, Interactor* i1, Alignment a2, Interactor* i2, TGlue* tg
) {
if (!AlreadyInserted(i1)) {
Insert(i1);
}
if (!AlreadyInserted(i2)) {
Insert(i2);
}
tsolver->AddAlignment(a1, i1, a2, i2, tg);
}
void Tray::Align (Alignment a, Interactor* i, TGlue* tg) {
if (!AlreadyInserted(i)) {
Insert(i);
}
tsolver->AddAlignment(a, i, tg);
}
static void LoadInteractorArray (
Interactor* i[], Interactor* i0, Interactor* i1,
Interactor* i2, Interactor* i3, Interactor* i4,
Interactor* i5, Interactor* i6
) {
i[0] = i0;
i[1] = i1;
i[2] = i2;
i[3] = i3;
i[4] = i4;
i[5] = i5;
i[6] = i6;
}
void Tray::Align (
Alignment a, Interactor* i0, Interactor* i1,
Interactor* i2, Interactor* i3, Interactor* i4,
Interactor* i5, Interactor* i6
) {
const int n = 7;
Interactor* i[n];
int k;
LoadInteractorArray(i, i0, i1, i2, i3, i4, i5, i6);
for (k = 0; k < n && i[k] != nil; ++k) {
if (!AlreadyInserted(i[k])) {
Insert(i[k]);
}
}
for (k = 1; k < n && i[k] != nil; ++k) {
tsolver->AddAlignment(a, i[k-1], a, i[k]);
}
}
void Tray::HBox (
Interactor* i0, Interactor* i1,
Interactor* i2, Interactor* i3, Interactor* i4,
Interactor* i5, Interactor* i6
) {
const int n = 7;
Interactor* i[n];
int k, last = n - 1;
LoadInteractorArray(i, i0, i1, i2, i3, i4, i5, i6);
for (k = 0; k < n && i[k] != nil; ++k) {
if (!AlreadyInserted(i[k])) {
Insert(i[k]);
}
}
for (k = 1; k < n && i[k] != nil; ++k) {
if (TrayOrBg(i[0]) && k == 1) {
tsolver->AddAlignment(Left, this, Left, i[1]);
} else if (TrayOrBg(i[k]) && (k == last || i[k+1] == nil)) {
tsolver->AddAlignment(Right, i[k-1], Right, this);
} else {
tsolver->AddAlignment(Right, i[k-1], Left, i[k]);
}
}
}
void Tray::VBox (
Interactor* i0, Interactor* i1,
Interactor* i2, Interactor* i3, Interactor* i4,
Interactor* i5, Interactor* i6
) {
const int n = 7;
Interactor* i[n];
int k, last = n - 1;
LoadInteractorArray(i, i0, i1, i2, i3, i4, i5, i6);
for (k = 0; k < n && i[k] != nil; ++k) {
if (!AlreadyInserted(i[k])) {
Insert(i[k]);
}
}
for (k = 1; k < n && i[k] != nil; ++k) {
if (TrayOrBg(i[0]) && k == 1) {
tsolver->AddAlignment(Top, this, Top, i[1]);
} else if (TrayOrBg(i[k]) && (k == last || i[k+1] == nil)) {
tsolver->AddAlignment(Bottom, i[k-1], Bottom, this);
} else {
tsolver->AddAlignment(Bottom, i[k-1], Top, i[k]);
}
}
}